#include "matrixMultiply.h"

__global__ void coalescedMultiply(MatType* A,  MatType* C,int N)
{
	// Block index
	int bx = blockIdx.x;
	int by = blockIdx.y;
	// Thread index
	int tx = threadIdx.x;
	int ty = threadIdx.y;
	// Index of the first sub-matrix of A processed by the block
	int aBegin = N * BLOCK_SIZE * by;
	// Index of the last sub-matrix of A processed     by the block
	int aEnd = aBegin + N - 1;
	// Step size used to iterate through the submatrices of A
	int aStep = BLOCK_SIZE;
	// Index of the first sub-matrix of B processed by the block
	int bBegin = BLOCK_SIZE * bx;
	// Step size used to iterate through the submatrices of B
	int bStep = BLOCK_SIZE * N;
	// The element of the block sub-matrix that is computed by the thread
	MatType Csub = 0;
	// Loop over all the sub-matrices of A and B required to
	// compute the block sub-matrix
	for (int a = aBegin, b = bBegin; a <= aEnd; a += aStep, b += bStep)
	{
		// Shared memory for the sub-matrix of A
		__shared__ MatType As[BLOCK_SIZE][BLOCK_SIZE+1];
		// Shared memory for the sub-matrix of B
		__shared__ MatType Bs[BLOCK_SIZE][BLOCK_SIZE+1];
		// Load the matrices from global memory to shared memory;
		// each thread loads one element of each matrix
		As[ty][tx] = A[a + N * ty + tx];
		Bs[ty][tx] = A[b + N * ty + tx];
		// Synchronize to make sure the matrices are loaded
		__syncthreads();
		// Multiply the two matrices together; each thread computes
		// one element of the block sub-matrix
		for (int k = 0; k < BLOCK_SIZE; ++k)
		{
			Csub |= As[ty][k] & Bs[k][tx];
		}
		// Synchronize to make sure that the preceding computation is done
		// before loading two new sub-matrices of A and B in the next iteration
		__syncthreads();
	}
	// Write the block sub-matrix to global memory;
	// each thread writes one element
	int c = N * BLOCK_SIZE * by + BLOCK_SIZE * bx;
	C[c + N * ty + tx] = Csub;
}